grammar Script;

import CommonLexer;

name: Identifier;

literal
    : DECIMAL_LITERAL
    | FLOAT_LITERAL
    | STRING_LITERAL
    | BOOL_LITERAL
    | NULL_LITERAL
    ;


variableDeclarator
    : variableDeclaratorId ('=' variableInitializer)?
    ;

variableDeclaratorId
    : name ('[' ']')*
    ;

parameters
    : '(' parameter? ')'
    ;

parameter
    : variableDeclaratorId (',' variableDeclaratorId)*
    ;

function: parameters block;

unit:
    literal
  | variableDeclaratorId
  | arr
  | function
  | json
;

pair: STRING_KEY ':' unit;
obj
   : '{' pair (',' pair)* '}'
   | '{' '}'
   ;
arr: '[' unit (',' unit)* ']'
   | '[' ']'
   ;
json: obj| arr;

variableInitializer
    : arrayInitializer
    | expression
    | json
    ;

arrayInitializer
    : '[' (variableInitializer (',' variableInitializer)* (',')? )? ']'
    ;


statement
    : block
    | IF parExpression block (ELSE statement)?
    | FOR '(' forControl ')' block
    | WHILE parExpression block
    | RETURN expression? ';'
    | BREAK ';'
    | CONTINUE ';'
    | SEMI
    | statExpression=expression ';'
    ;


forControl
    : forInit? ';' expression? ';' forUpdate=expressionList?
    ;

forInit
    : variableDeclarator
    | expressionList
    ;

parExpression
    : '(' expression ')'
    ;

expressionList
    : expression (',' expression)*
    ;

functionCall
    : name '(' expressionList? ')'
    ;

expression
    : primary
    | expression bop='.' (name | functionCall)
    | expression '[' expression ']'
    | functionCall
    | expression postfix=('++' | '--')
    | expression bop=('*'|'/'|'%') expression
    | expression bop=('+'|'-') expression
    | expression bop=('<=' | '>=' | '>' | '<' | '==' | '!=') expression
    | expression bop=('&&' | '||') expression
    | expression bop='?' expression ':' expression
    | <assoc=right> expression bop=('=' | '+=' | '-=' | '*=' | '/=' | '%=') expression
    ;

primary
    : '(' expression ')'
    | literal
    | name
    ;

blockStatement
    : variableDeclarator (';')?
    | statement
    ;

blockStatements
    : blockStatement*
    ;

block
    : '{' blockStatements '}'
    ;

prog
    : blockStatements
    ;